﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections.Concurrent;
using Newtonsoft.Json;
using Parylene_CVD.Model;
using Parylene_CVD.Tools;
using System.IO;
using Parylene_CVD.DAL;
using Parylene_CVD.Model.DModels;
using System.Security.Cryptography;
using System.IO.Compression;
using Parylene_CVD.Views;
using AlarmEvent = Parylene_CVD.Model.AlarmEvent;
using System.Windows;

namespace Parylene_CVD.DataTransfer
{
    public class WebSocketServer
    {
        static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); // 日志记录
        private readonly HttpListener _httpListener; // 用于监听客户端连接
        private readonly ConcurrentDictionary<string, WebSocket> _connectedClients = new(); // 客户端连接池
        private readonly CancellationTokenSource _cancellationTokenSource = new(); // 用于控制任务的取消

        /// <summary>
        /// 初始化服务端，并设置监听的地址
        /// </summary>
        /// <param name="urlPrefix"></param>
        public WebSocketServer(string urlPrefix)
        {
            _httpListener = new HttpListener();
            _httpListener.Prefixes.Add(urlPrefix); // e.g., "http://localhost:5000/ws/"
        }
        // 启动服务
        public async Task StartAsync()
        {
            _httpListener.Start();
            logger.Info("服务器启动...");

            while (!_cancellationTokenSource.Token.IsCancellationRequested)
            {
                try
                {
                    var context = await _httpListener.GetContextAsync();
                    if (context.Request.IsWebSocketRequest)
                    {
                        // 开始处理客户端连接
                        _ = Task.Run(() => HandleClientAsync(context)); // 异步处理每个客户端
                    }
                    else
                    {
                        // 非 WebSocket 请求，返回 400 状态码
                        context.Response.StatusCode = 400;
                        context.Response.Close();
                    }
                }
                catch (Exception ex)
                {
                    logger.Info($"服务器运行过程异常: {ex.Message}");
                }
            }
        }

        // 处理客户端连接
        private async Task HandleClientAsync(HttpListenerContext context)
        {
            WebSocket webSocket = null;
            try
            {
                // 接受 WebSocket 请求
                var webSocketContext = await context.AcceptWebSocketAsync(null); // null 表示不指定子协议
                webSocket = webSocketContext.WebSocket;

                // 开始处理 WebSocket 消息
                await HandleMessagesAsync(webSocket); // 传递 WebSocket，处理消息
            }
            catch (Exception ex)
            {
                logger.Info($"处理客户端连接异常: {ex.Message}");
            }
            finally
            {
                if (webSocket != null && webSocket.State != WebSocketState.Closed)
                {
                    await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
                }
            }
        }

        // 处理 WebSocket 消息
        private async Task HandleMessagesAsync(WebSocket webSocket)
        {
            var buffer = new byte[1024 * 1024]; // 设置缓冲区大小为 1MB
            WebSocketReceiveResult result = null;
            string deviceName = null;

            try
            {
                while (webSocket.State == WebSocketState.Open)
                {
                    result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    string message = Encoding.UTF8.GetString(buffer, 0, result.Count);

                    // 仅在第一次接收时提取设备名
                    if (deviceName == null)
                    {
                        var initialMessage = JsonConvert.DeserializeObject<dynamic>(message);
                        deviceName = initialMessage?.ClientId; // 提取设备名
                        logger.Info($"客户端 {deviceName} 已连接。"); // 打印连接日志
                    }

                    // 如果接收到关闭请求
                    if (result.MessageType == WebSocketMessageType.Close)
                    {
                        // 客户端请求关闭连接
                        await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "关闭", CancellationToken.None);
                        break; // 退出循环
                    }
                    else if (result.MessageType == WebSocketMessageType.Text)
                    {
                        // 处理文本消息
                        logger.Info($"收到来自 {deviceName} 的消息：{message}");

                        // 解析消息
                        var jsonMessage = JsonConvert.DeserializeObject<dynamic>(message);
                        string messageType = jsonMessage?.Type;

                        // 根据消息类型调用不同的处理函数
                        switch (messageType)
                        {
                            case "RealTimeData":
                                await HandleRealTimeDataAsync(jsonMessage?.Data,deviceName);
                                break;
                            case "AlarmData":
                                await HandleAlarmDataAsync(jsonMessage?.Data, deviceName);
                                break;
                            case "DeviceStatus":
                                await HandleDeviceStatusAsync(jsonMessage?.Data,deviceName);
                                break;
                            case "FileChunk":
                                await HandleFileChunkAsync(jsonMessage);
                                break;
                            default:
                                logger.Warn($"收到未知类型的消息：{messageType}");
                                break;
                        }

                        // 可选择发送回消息给客户端（Echo）
                        var responseMessage = $"回声: {message}";
                        var responseBytes = Encoding.UTF8.GetBytes(responseMessage);
                        await webSocket.SendAsync(new ArraySegment<byte>(responseBytes), WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
            }
            catch (Exception ex)
            {
                // 错误处理
                logger.Info($"处理 WebSocket 时发生错误: {ex.Message}");
            }
            finally
            {
                // 确保关闭 WebSocket 连接
                if (webSocket.State != WebSocketState.Closed)
                {
                    await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "关闭", CancellationToken.None);
                }
                logger.Info($"客户端 {deviceName} 已断开连接。");
            }
        }
        /// <summary>
        /// 接收报警数据处理逻辑
        /// </summary>
        /// <param name="data"></param>
        /// <param name="deviceName"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private async Task HandleAlarmDataAsync(dynamic? data, string? deviceName)
        {
            // 实现接收报警数据的处理逻辑
            try
            {
                if (data == null || deviceName == null)
                {
                    logger.Warn("接收到的报警数据为空或设备名称未指定。");
                    return;
                }
                // 将 dynamic 类型的数据报警类型
                var alarmEvents = JsonConvert.DeserializeObject<List<AlarmEvent>>(JsonConvert.SerializeObject(data));

                if (alarmEvents == null || alarmEvents.Count == 0)
                {
                    logger.Warn($"设备 {deviceName} 发送的报警数据为空。");
                    return;
                }
                logger.Info($"处理来自设备 {deviceName} 的报警数据，共 {alarmEvents.Count} 条。");

                // 弹出提示框显示报警信息
                foreach (var alarmEvent in alarmEvents)
                {
                    // 生成报警消息
                    string alarmMessage = $"设备: {deviceName}\n" +
                                          $"报警类型: {alarmEvent.AlarmType}\n" +
                                          $"报警时间: {alarmEvent.AlarmStartTime}";

                    // 弹出提示框
                    MessageBox.Show(alarmMessage, "报警提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                }
                // 保存到数据库
                await SaveAlarmToDatabaseAsync(alarmEvents);

                logger.Info($"来自设备 {deviceName} 的报警数据处理完成。");
            }
            catch (Exception ex)
            {
                logger.Error($"接收报警数据时发生错误: {ex.Message}");
            }
        }
        /// <summary>
        /// 将接收到的报警数据保存到数据库
        /// </summary>
        /// <param name="alarmEvents"></param>
        /// <returns></returns>
        private async Task SaveAlarmToDatabaseAsync(List<AlarmEvent> alarmEvents)
        {
            List<AlarmEvents> alarmEventsList = new List<AlarmEvents>();
            foreach (AlarmEvent alarmEvent in alarmEvents) {
                AlarmEvents tempAlarmEvents = new AlarmEvents();
                tempAlarmEvents.DeviceAlarmEventId = alarmEvent.DeviceAlarmEventId;
                tempAlarmEvents.AlarmType = alarmEvent.AlarmType;
                tempAlarmEvents.AlarmLevel = alarmEvent.AlarmLevel;
                tempAlarmEvents.AlarmStartTime = alarmEvent.AlarmStartTime;
                tempAlarmEvents.AlarmEndTime = alarmEvent.AlarmEndTime;
                tempAlarmEvents.AlarmConfirmTime = alarmEvent.AlarmConfirmTime;
                tempAlarmEvents.DeviceID = GetDeviceIDByName(alarmEvent.DeviceName);
                alarmEventsList.Add(tempAlarmEvents);
            }
            AlarmEventsDAL alarmEventsDAL = new AlarmEventsDAL();
            alarmEventsDAL.AddListAlarmEvents(alarmEventsList, "");
        }
        /// <summary>
        /// 根据设备名返回设备ID
        /// </summary>
        /// <param name="deviceName"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private int GetDeviceIDByName(string deviceName)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            Device device =  deviceDAL.GetDevice("DeviceName = '" + deviceName + "'", "")[0];
            return device.DeviceId;
        }





        // 停止服务并关闭所有连接
        public async Task StopAsync()
        {
            _cancellationTokenSource.Cancel();

            // 异步关闭所有 WebSocket 客户端连接
            var closeTasks = _connectedClients.Values.Select(client =>
                client.CloseAsync(WebSocketCloseStatus.NormalClosure, "服务器关闭", CancellationToken.None));

            // 等待所有关闭操作完成
            await Task.WhenAll(closeTasks);

            // 停止 HTTP 监听器
            _httpListener.Stop();

            logger.Info("服务器已停止");
        }



        /// <summary>
        /// 接收实时数据的处理逻辑
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private async Task HandleRealTimeDataAsync(dynamic data,string deviceName)
        {
            // 实现实时数据的处理逻辑
            try
            {
                var realTimeData = JsonConvert.DeserializeObject<RealTimeData>(data.ToString());
                //logger.Info($"处理实时数据：{realTimeData}");
                // 如果已经有当前设备数据那么进行更新，如果没有直接添加
                if (DeviceRealDataTools.GetDeviceData(deviceName) == null) {
                    DeviceRealDataTools.AddDeviceData(deviceName, realTimeData);
                }
                else
                {
                    DeviceRealDataTools.UpdateDeviceData(deviceName, realTimeData);
                }
            }
            catch (Exception ex)
            {
                logger.Error($"处理实时数据时发生错误: {ex.Message}");
            }
        }
        /// <summary>
        /// 接收设备状态的处理逻辑
        /// </summary>
        /// <param name="data"></param>
        /// <param name="deviceName"></param>
        /// <returns></returns>
        private async Task HandleDeviceStatusAsync(dynamic data, string deviceName)
        {
            // 实现接收设备状态的处理逻辑
            try
            {
                //var realTimeData = JsonConvert.DeserializeObject<RealTimeData>(data.ToString());
                // 设置 IsStandby 为 true，其余状态为 false
                var targetDevice = GlobalVariables.deviceWithStatuses?.FirstOrDefault(device => device.DeviceName == deviceName);
                if (targetDevice != null)
                {
                    if (data == 1)
                    {
                        targetDevice.IsStandby = true;
                        targetDevice.IsCoating = false;
                        targetDevice.IsShutdown = false;
                    }
                    else if (data == 2)
                    {
                        targetDevice.IsStandby = false;
                        targetDevice.IsCoating = true;
                        targetDevice.IsShutdown = false;
                    }
                    else
                    {
                        targetDevice.IsStandby = false;
                        targetDevice.IsCoating = false;
                        targetDevice.IsShutdown = true;
                    }
                    
                }
                else
                {
                    logger.Error($"处理设备状态数据时发生异常");
                }

                
            }
            catch (Exception ex)
            {
                logger.Error($"处理设备状态数据时发生错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 接收数据文件处理逻辑
        /// </summary>
        /// <param name="jsonMessage">包含文件块的消息</param>
        /// <returns></returns>
        private static readonly Dictionary<string, FileChunkData> FileChunksCache = new();

        private class FileChunkData
        {
            public string FileName { get; set; }
            public int TotalChunks { get; set; }
            public int ReceivedChunks { get; set; }
            public byte[][] Chunks { get; set; }
            public string expectedFileHash { get; set; }
            
            public DateTime LastUpdated { get; set; } // 用于超时清理
        }

        private async Task HandleFileChunkAsync(dynamic? jsonMessage)
        {
            // 处理文件块前清理过期缓存
            CleanUpExpiredCache();
            try
            {
                // 解析消息中的字段
                string deviceName = jsonMessage?.ClientId;
                string fileName = jsonMessage?.FileName;
                int chunkIndex = jsonMessage?.ChunkIndex;
                int totalChunks = jsonMessage?.TotalChunks;
                string base64Data = jsonMessage?.Data;
                string fileHash = jsonMessage?.FileHash;

                if (string.IsNullOrEmpty(deviceName) || string.IsNullOrEmpty(fileName) || totalChunks <= 0 || chunkIndex < 0 || string.IsNullOrEmpty(base64Data) || string.IsNullOrEmpty(fileHash))
                {
                    logger.Warn("文件块消息字段不完整，处理失败。");
                    return;
                }

                // Base64 解码当前块数据
                byte[] compressedChunkBytes = Convert.FromBase64String(base64Data);

                // 解压缩数据
                byte[] chunkBytes = Decompress(compressedChunkBytes);

                // 为每个文件维护缓存
                string fileKey = $"{deviceName}:{fileName}";
                if (!FileChunksCache.ContainsKey(fileKey))
                {
                    FileChunksCache[fileKey] = new FileChunkData
                    {
                        FileName = fileName,
                        TotalChunks = totalChunks,
                        ReceivedChunks = 0,
                        Chunks = new byte[totalChunks][],
                        LastUpdated = DateTime.Now,
                        expectedFileHash = fileHash
                    };

                    logger.Info($"开始接收文件：{fileName}（设备：{deviceName}，总块数：{totalChunks}）");
                }

                var fileChunkData = FileChunksCache[fileKey];

                // 检查是否已接收到此块
                if (fileChunkData.Chunks[chunkIndex] != null)
                {
                    logger.Warn($"文件块 {chunkIndex + 1}/{totalChunks} 已接收，忽略重复块。");
                    return;
                }

                // 保存当前块到缓存
                fileChunkData.Chunks[chunkIndex] = chunkBytes;
                fileChunkData.ReceivedChunks++;
                fileChunkData.LastUpdated = DateTime.Now;

                logger.Info($"已接收文件块 {chunkIndex + 1}/{totalChunks}，设备：{deviceName}");

                // 检查是否所有块都接收完毕
                if (fileChunkData.ReceivedChunks == totalChunks)
                {
                    logger.Info($"文件接收完成：{fileName}（设备：{deviceName}）");

                    // 拼接所有块
                    byte[] completeFile = fileChunkData.Chunks.SelectMany(b => b).ToArray();
                    string receivedFileHash = CalculateFileHash(completeFile);
                    if (receivedFileHash == fileChunkData.expectedFileHash)
                    {
                        logger.Info($"文件 {fileChunkData.FileName} 接收成功且完整！");
                        // 查询保存目录
                        ParameterDAL parameterDAL = new ParameterDAL();
                        Parameter parameterSavePath = parameterDAL.GetParameter("ParameterName = '数据保存目录'", "").FirstOrDefault();
                        if (parameterSavePath == null)
                        {
                            logger.Error("无法获取数据保存目录参数，请检查配置。");
                            return;
                        }
                        string directory = parameterSavePath.ParameterValue;

                        // 保存文件到服务器
                        string saveDirectory = Path.Combine(directory, deviceName);
                        Directory.CreateDirectory(saveDirectory); // 确保目录存在
                        string savePath = Path.Combine(saveDirectory, fileName);
                        await File.WriteAllBytesAsync(savePath, completeFile);

                        logger.Info($"文件已保存到：{savePath}");

                        // 从缓存中移除文件信息
                        FileChunksCache.Remove(fileKey);
                    }
                    else
                    {
                        logger.Error($"文件 {fileChunkData.FileName} 接收完整但校验失败！");
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error($"处理文件块时发生错误：{ex.Message}");
            }
        }

        /// <summary>
        /// 解压缩字节数据（GZip）
        /// </summary>
        /// <param name="compressedData">压缩后的字节数组</param>
        /// <returns>解压后的字节数组</returns>
        private byte[] Decompress(byte[] compressedData)
        {
            using (var compressedStream = new MemoryStream(compressedData))
            using (var decompressedStream = new MemoryStream())
            using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
            {
                gzip.CopyTo(decompressedStream);
                return decompressedStream.ToArray();
            }
        }

        /// <summary>
        /// 哈希计算 文件完整性校验
        /// </summary>
        /// <param name="fileContent"></param>
        /// <returns></returns>
        private string CalculateFileHash(byte[] fileContent)
        {
            using (var sha256 = SHA256.Create())
            {
                byte[] hashBytes = sha256.ComputeHash(fileContent);
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
            }
        }

        private static readonly TimeSpan CacheTimeout = TimeSpan.FromMinutes(10); // 缓存超时时间
        private static readonly object CacheLock = new(); // 用于线程安全的锁

        /// <summary>
        /// 定时清理缓存
        /// </summary>
        public static void StartCacheCleanupTask()
        {
            Task.Run(async () =>
            {
                while (true)
                {
                    await Task.Delay(TimeSpan.FromMinutes(5)); // 每隔 5 分钟执行一次清理
                    CleanUpExpiredCache();
                }
            });
        }

        /// <summary>
        /// 清理过期的缓存条目
        /// </summary>
        private static void CleanUpExpiredCache()
        {
            lock (CacheLock) // 确保线程安全
            {
                DateTime now = DateTime.Now;
                var expiredKeys = FileChunksCache
                    .Where(kvp => (now - kvp.Value.LastUpdated) > CacheTimeout)
                    .Select(kvp => kvp.Key)
                    .ToList();

                foreach (var key in expiredKeys)
                {
                    FileChunksCache.Remove(key);
                    logger.Warn($"清理过期的缓存：{key}");
                }
            }
        }


    }
}
